package com.hk.core.authentication.security;

import com.hk.core.authentication.api.AuthenticationException;
import com.hk.core.authentication.api.SecurityContext;
import com.hk.core.authentication.api.UserPrincipal;
import lombok.Setter;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.Objects;
import java.util.function.Function;

/**
 * 使用 Spring Security 获取当前登陆用户信息
 *
 * @author kevin
 */
public class SpringSecurityContext implements SecurityContext {

    /**
     * 获取用户最新的信息：
     * 定义这个的目的: 当用户修改了用户上下信息时，如果用户已登陆，用户的信息存放在session or 当前上下文中，
     * 这个用户信息并不是修改后的用户最新信息，如果想要获取用户最新的信息，可以通过此方法来获取
     */
    @Setter
    private Function<UserPrincipal, ? extends UserPrincipal> function;

    @Override
    public <T extends UserPrincipal> T getPrincipalByType(Class<T> type) {
        var authentication = SecurityContextHolder.getContext().getAuthentication();
        if (Objects.nonNull(authentication) &&
                !(authentication instanceof AnonymousAuthenticationToken)
                && authentication.isAuthenticated()) {
            var principal = (UserPrincipal) authentication.getPrincipal();
            if (Objects.nonNull(function)) {
                principal = function.apply(principal);
            }
            return type.cast(principal);
        }
        throw new AuthenticationException("未认证的用户");
    }

    /**
     * 当前用户是否有登陆，不包括匿名用户
     *
     * @return 登陆返回true, 否则返回false
     */
    @Override
    public boolean isAuthenticated() {
        var authentication = SecurityContextHolder.getContext().getAuthentication();
        return Objects.nonNull(authentication) && !(authentication instanceof AnonymousAuthenticationToken)
                && authentication.isAuthenticated();
    }

}
